/**
 * Program : Lembar Kerja 04, Hierarchical Modelling
 *           Lighting, Shadow, and Texture, Worksheet 4
 * Berkas  : functions.h
 * ----------------------------------------------
 * Nama Pembuat :
 *  - Andry Luthfi, (0906629044)
 *  - Hadi Saputro, (0906562871)
 *
 * Aplikasi ini mengimplementasikan konsep Objek Hirarkis
 * serta teknik-teknik pencahayaan pada OpenGL. konsep-konsep
 * didapatkan pada mata kuliah Grafika Komputer.
 *
 * berkas ini berisikan fungsi pembantu program.
 *
 * Hak Cipta (c) 2012, Andry Luthfi, Hadi Saputro
 */


void glutWireCylinder(GLUquadricObj *obj, GLdouble base, GLdouble top, GLdouble height, GLint slices,  GLint stacks){
    gluQuadricDrawStyle(obj, GLU_LINE); //wireframe mode
    gluCylinder(obj, top, base, height, stacks, slices);
}

void glutSolidCylinder(GLUquadricObj *obj, GLdouble base, GLdouble top, GLdouble height, GLint slices,  GLint stacks){
    gluQuadricDrawStyle(obj, GLU_FILL); //wireframe mode
    gluCylinder(obj, top, base, height, stacks, slices);
}

void glShadowProjection(float * l, float * e, float * n) {
    float d, c;
    float mat[16];

    // These are c and d (corresponding to the tutorial)

    d = n[0] * l[0] + n[1] * l[1] + n[2] * l[2];
    c = e[0] * n[0] + e[1] * n[1] + e[2] * n[2] - d;

    // Create the matrix. OpenGL uses column by column
    // ordering

    mat[0] = l[0] * n[0] + c;
    mat[4] = n[1] * l[0];
    mat[8] = n[2] * l[0];
    mat[12] = -l[0] * c - l[0] * d;

    mat[1] = n[0] * l[1];
    mat[5] = l[1] * n[1] + c;
    mat[9] = n[2] * l[1];
    mat[13] = -l[1] * c - l[1] * d;

    mat[2] = n[0] * l[2];
    mat[6] = n[1] * l[2];
    mat[10] = l[2] * n[2] + c;
    mat[14] = -l[2] * c - l[2] * d;

    mat[3] = n[0];
    mat[7] = n[1];
    mat[11] = n[2];
    mat[15] = -d;

    // Finally multiply the matrices together *plonk*
    glMultMatrixf(mat);
}

void updRotationAngle() {
	lamp1_pos_rot[0] = ((cos(light_angle * 3.14/180)) * 28);
	lamp1_pos1[0] = ((cos(light_angle * 3.14/180)) * 28);
	lamp1_pos[0] = ((cos(light_angle * 3.14/180)) * 28);

	lamp1_pos_rot[2] = ((sin(light_angle * 3.14/180)) *28);
	lamp1_pos1[2] = ((sin(light_angle * 3.14/180)) *28);
	lamp1_pos[2] = ((sin(light_angle * 3.14/180)) *28);

}

/**
 * fungsi delay sederhana menggunankan pendekatan loop
 */
void delay() {
    int a = 0;
    int b = 0;
    for (a = 0; a < 1000; a++) {
        for (b = 0; b < 2000; b++)
            ;
    }
}

void menu_texture(int id) {

    switch(id){
        case 0 : isTexture_s = !(isTexture_s); break;
        case 1 : isTexture_m = !(isTexture_m); break;
        case 2 : isTexture_s = !(isTexture_s); isTexture_m = !(isTexture_m); break;
    }
    printf("%d\n",isTexture_s);
}

void glSetMaterial(GLfloat* specular, GLfloat* ambient, GLfloat* diffuse, GLfloat shininess) {
    glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
    glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
    glMaterialf(GL_FRONT, GL_SHININESS, shininess);
}

void textureOn() {
	//to handle the textures generation and coordinates
	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE); // Set The Texture Generation Mode
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_PLANE); // Set The Texture Generation Mode
    glTexGenfv(GL_S, GL_OBJECT_PLANE, slanted);
    glTexGenfv(GL_T, GL_OBJECT_PLANE, slanted);

	//enable texture
	glEnable(GL_TEXTURE_2D);
}

GLuint LoadTexture(const char * filename, int wrap) {
    GLuint textures;
    int width, height;
    unsigned char * data;
    FILE * file;
    // open texture data
    file = fopen(filename, "rb");
    if (file == NULL) return 0;

    // allocate buffer
    width = 64;
    height = 128;
    data = (unsigned char *) malloc(width * height * 3);

    // read texture data
    fread(data, width * height * 3, 1, file);
    fclose(file);

    // allocate a texture name
    glGenTextures(1, &textures);
    // select our current texture
    glBindTexture(GL_TEXTURE_2D, textures);
    /* glBindTexture ? bind a named texture to a texturing target
     */

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    /* set texture environment parameters
     */

    // when texture area is small, bilinear filter the closest MIP map
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
            GL_LINEAR_MIPMAP_NEAREST);
    /* set texture parameters
     */

    // when texture area is large, bilinear filter the first MIP map
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // if wrap is true, the texture wraps over at the edges (repeat)
    //       ... false, the texture ends at the edges (clamp)
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
            wrap ? GL_REPEAT : GL_CLAMP);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
            wrap ? GL_REPEAT : GL_CLAMP);

	// select modulate to mix texture with color for shading
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    // build our texture MIP maps
    gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width,
            height, GL_RGB, GL_UNSIGNED_BYTE, data);

    // free buffer
    free(data);

    return textures;

}
#define PI 3.14

void changeView(){
    /*if (view == VIEW_ALL){
        gluLookAt(cameraPositionX, cameraPositionY, cameraPositionZ, cameraLookX, cameraLookY, cameraLookZ, 0.0, 1.0, 0.0);
    } else {
        gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    }*/
    switch(view){
        case VIEW_ALL :
            gluLookAt(cameraPositionX, cameraPositionY, cameraPositionZ, cameraLookX, cameraLookY, cameraLookZ, 0.0, 1.0, 0.0);
            break;
        case VIEW_SPIDER :
            //glRotatef(180-theta[0], 0.0,1.0,0.0);
            gluLookAt(7.0*sin(theta[0]*PI/180), 0.0, 7.0*cos(theta[0]*PI/180), 30.0*sin(theta[0]*PI/180), 0.0, 30.0*cos(theta[0]*PI/180), 0.0, 1.0, 0.0);
            break;

        case VIEW_MOKU :
            //glTranslatef(20.0, 0.0, -10.0);
            //gluLookAt(17.5 , 10.0, -10.0, -60.0, 10.0, -10.0, 0.0, 1.0, 0.0);
            //gluLookAt(22.5 , 10.0, -10.0, 40.0, 10.0, -10.0, 0.0, 1.0, 0.0);
            gluLookAt(20.0 + (2.5*sin(theta[0]*PI/180)) , 10.0, -10 + (2.5*cos(theta[0]*PI/180)), 20.0 + (40*sin(theta[0]*PI/180)), 10.0, -10 + (40*cos(theta[0]*PI/180)), 0.0, 1.0, 0.0);
            break;
    }
}
